package com.vip.jwt.config;

import cn.hutool.json.JSONUtil;
import com.vip.jwt.common.entity.R;
import com.vip.jwt.common.exception.ExceptionEnum;
import com.vip.jwt.common.utils.JwtUtil;
import com.vip.jwt.common.utils.ServlertUtil;
import lombok.Getter;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMethod;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class JwtFilter extends AccessControlFilter {

    @Getter
    private final static String AUTHORIZATION = "Authorization";
    @Getter
    private final static String PLATFORM = "Platform";

    @Override
    protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception {
        //解决跨域问题
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse;
        httpServletResponse.setHeader("Access-control-Allow-Origin", httpServletRequest.getHeader("Origin"));
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS,PUT,DELETE");
        httpServletResponse.setHeader("Access-Control-Allow-Headers", httpServletRequest.getHeader("Access-Control-Request-Headers"));
        //跨域时会首先发送一个option请求，这里我们给option请求直接返回正常状态
        if (httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name())) {
            httpServletResponse.setStatus(HttpStatus.OK.value());
            return true;
        }
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        //这个地方和前端约定，要求前端将jwtToken放在请求的Header部分
        //所以以后发起请求的时候就需要在Header中放一个Authorization，值就是对应的Token
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String platform = request.getHeader(PLATFORM);
        String token = request.getHeader(AUTHORIZATION);
        JwtToken jwtToken = new JwtToken(token);
        /*
         * 下面就是固定写法
         * */
        try {
            //验证Redis中是否有此用户登录
            String username = JwtUtil.getUsername(token);
            boolean bo = JwtUtil.verify(request,username,token);
            if(!bo){
                error(servletResponse,ExceptionEnum.TOKEN_INVALID);
                return false;
            }
            //委托 realm 进行登录认证
            //所以这个地方最终还是调用JwtRealm进行的认证
            //也就是subject.login(token)
            //loginType为需要哪个Realm进行认证
            if("XCX".equals(platform)){
                getSubject(servletRequest, servletResponse).login(new MyUsernamePasswordToken(jwtToken,"XCXRealm"));
            }else{
                getSubject(servletRequest, servletResponse).login(new MyUsernamePasswordToken(jwtToken,"MyRealm"));
            }
        } catch (Exception e) {
            e.printStackTrace();
            error(servletResponse,ExceptionEnum.TOKEN_INVALID);
            //调用下面的方法向客户端返回错误信息
            return false;
        }
        return true;
    }

    /**
     *  OPTION跨域预检
     * @param response
     */
    private void success(ServletResponse response){
        String msgStr = "OPTION跨域请求预检成功";
        R r = R.ok().code(HttpStatus.OK.value()).message(msgStr);
        String msg = JSONUtil.toJsonStr(r);
        ((HttpServletResponse)response).setStatus(HttpStatus.OK.value());
        ServlertUtil.outputSteam(msg,response);
    }

    /**
     * 验证错误
     * @param response
     */
    private void error(ServletResponse response, ExceptionEnum exceptionEnum){
        R r = R.error().code(exceptionEnum.getCode()).message(exceptionEnum.getMessage());
        String msg = JSONUtil.toJsonStr(r);
        ((HttpServletResponse)response).setStatus(exceptionEnum.getCode());
        ServlertUtil.outputSteam(msg,response);
    }

}
